
package jdx_11_AtomicXxxx;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 解决同样的问题的更高效的方法，使用AtomXXX类
 * AtomXXX类本身方法都是原子性的，但不能保证多个方法连续调用是原子性的
 */


/*
这里使用 AtomicInteger 完成上一个小程序的功能（上个程序的代码已经注释掉了）
 */

public class T01_AtomicInteger {
	/*volatile*/ //int count1 = 0;

	AtomicInteger count = new AtomicInteger(0); //Atomic开头的类底层都是用CAS保证线程的安全性

	/*synchronized*/ void m() {
		for (int i = 0; i < 10000; i++)
			//if count1.get() < 1000
			count.incrementAndGet(); //count1++
		/*
		底层的源码:
	public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

    	接下来进入:getAndAddInt()

	public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
    	这里又调用了 compareAndSwapInt 的方法 这就是 CAS(CompareAndSet)

		 */
	}

	public static void main(String[] args) {
		T01_AtomicInteger t = new T01_AtomicInteger();

		List<Thread> threads = new ArrayList<Thread>();

		for (int i = 0; i < 10; i++) {
			threads.add(new Thread(t::m, "thread-" + i));
		}

		threads.forEach((o) -> o.start());

		threads.forEach((o) -> {
			try {
				o.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		System.out.println(t.count);
	}
}

/*

CAS的流程
cas(V,Expected,NewValue){
	-if V==E
	V = NewValue
	otherwise try again or fail
}

在CAS操作中，第一个参数是我想要修改的值，第二个参数是我期望当前被修改的值是多少，
举个例子，现在我用CAS来修改一个值为1的数据，当我的线程过来访问这个数据时，
我这个线程自然就希望它的值就是1(期望值)，如果不是1的话，说明这个值被别的线程修改过了，
如果这个数据被改过了，此时我的这个线程自然就不能对它修改，否则就出错了，在这种情况下，
当前的线程就会尝试重新期望(或者错误退出)

假设原本数据为1的值被修改成了5，那么重新期望的值也会是5，否则就代表这个数据又被别的线程修改过了...

[问题]假设在CAS判断这个值是否相等的时候，别的线程刚好也修改了数据，怎么办？
不需要担心这个问题，因为底层是由CPU原语支持

[ABA问题]
就是在CAS操作之前，一个数据原本是1，后来被别的线程修改为2之后再次修改回1，这就是ABA问题。

这个问题其实原本上没有关系的(因为我这里举的例子中要被修改的数据假设是 int 类型的)，
不过要是处理的数据是一个对象，我们要想解决也是可以解决的，就是给需要修改的数据增加版本号。

AtomicStampedReference 就是这样的一个原理 代码中加了一个 stamp(戳)

总之：
- 基础类型，无所谓
- 引用类型，可以增加一个版本号解决对象不一致问题(对象中的属性被修改后，难以保证对象的行为是否发生改变)

[补充]:
CAS很多人的叫法不同：乐观锁，无锁优化，自旋锁
 */





